﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xaml;
using UIT.Markup;
using System.Collections;
using System.Reflection;

namespace UIT
{
    public class UitXamlObjectReader : XamlObjectReader
    {
        public UitXamlObjectReader(object instance)
            : base(instance)
        {
        }

        public UitXamlObjectReader(object instance, XamlSchemaContext xamlSchemaContext, XamlObjectReaderSettings xamlObjectReaderSettings)
            : base(instance, xamlSchemaContext, xamlObjectReaderSettings)
        {
            Settings = xamlObjectReaderSettings;
        }

        Stack instances = new Stack();
        private bool readingBinding;
        private Binding value;
        private XamlMember member;
        private XamlObjectReader bindingReader;
        private bool startedReading;

        public override bool Read()
        {
            if (readingBinding)
            {
                if (!startedReading)
                {
                    while (bindingReader.NodeType != XamlNodeType.StartObject)
                        bindingReader.Read();
                    startedReading = true;
                    return true;
                }
                else if (bindingReader.Read())
                    return true;
            }
            bool result = base.Read();
            if (NodeType == XamlNodeType.StartMember)
            {
                IBindingContainer binder = instances.Peek() as IBindingContainer;
                if (binder != null)
                {
                    Binding b = binder.GetBinding(base.Member.Name);
                    if (b == null)
                    {
                        object[] defaultValue = base.Member.UnderlyingMember.GetCustomAttributes(typeof(System.ComponentModel.DefaultValueAttribute), true);
                        if (defaultValue != null && defaultValue.Length > 0)
                        {
                            if (((PropertyInfo)base.Member.UnderlyingMember).GetValue(instances.Peek(), null) == ((System.ComponentModel.DefaultValueAttribute)defaultValue[0]).Value)
                            {
                                while (NodeType != XamlNodeType.EndMember)
                                    base.Read();
                                return Read();
                            }
                        }
                        else
                        {
                            if (((PropertyInfo)base.Member.UnderlyingMember).GetValue(instances.Peek(), null) == null)
                            {
                                while (NodeType != XamlNodeType.EndMember)
                                    base.Read();
                                return Read();
                            }
                        }
                    }
                    else
                    {
                        value = new UIT.Markup.Binding(b.Mode, b.Path, b.Source, b.StringFormat);
                        member = new XamlMember((PropertyInfo)Member.UnderlyingMember, SchemaContext, new BindingMemberInvoker(Member.Name, value));
                        bindingReader = new XamlObjectReader(value, this.SchemaContext, this.Settings);
                        readingBinding = true;
                        return true;
                    }
                }
            }
            if (NodeType == XamlNodeType.EndMember && readingBinding)
            {
                value = null;
                startedReading = false;
                readingBinding = false;
            }
            if (NodeType == XamlNodeType.StartObject)
                instances.Push(Instance);
            if (NodeType == XamlNodeType.EndObject)
            {
                instances.Pop();
            }

            return result;
        }

        public override XamlNodeType NodeType
        {
            get
            {
                if (readingBinding && startedReading)
                    return bindingReader.NodeType;
                return base.NodeType;
            }
        }

        public override XamlMember Member
        {
            get
            {
                if (readingBinding && startedReading)
                    return bindingReader.Member;
                return base.Member;
            }
        }

        public override XamlType Type
        {
            get
            {
                if (readingBinding)
                {
                    if (startedReading)
                        return bindingReader.Type;
                    return new XamlType(typeof(Binding), SchemaContext);
                }
                return base.Type;
            }
        }

        public override object Value
        {
            get
            {
                if (readingBinding)
                    return bindingReader.Value;
                return base.Value;
            }
        }

        public override object Instance
        {
            get
            {
                if (readingBinding)
                    return bindingReader.Instance;
                return base.Instance;
            }
        }

        public XamlObjectReaderSettings Settings { get; set; }
    }
}
